COMP3141
Software System Design and Implementation (18s1)

Exercise (Week 8)

Table of Contents

Ex06-icon.png

DUE: 29 April, 2018 23:55

Download the exercise tarball and extract it to a directory in your home directory at CSE. This tarball contains a file, called Ex06.hs, wherein you will do all of your programming.

To test your code, run the following shell commands to open a GHCi session:

$ 3141
newclass starting new subshell for class COMP3141...
$ cabal repl
Resolving dependencies...
Configuring Ex06-1.0...
Preprocessing executable 'Ex06' for Ex06-1.0..
GHCi, version 8.2.2: http://www.haskell.org/ghc/  :? for help
[1 of 1] Compiling Ex06          (Ex06.hs, interpreted)
Ok, one module loaded.
*Ex06> let f = L "Hi " $ S $ L "! You're " $ I $ L "years old" $ X
*Ex06> printf f "Bob" 3
...

Note that you will only need to submit Ex06.hs, so only make changes to that file.

Download the exercise tarball and extract it to a directory on your local machine. This tarball contains a file, called Ex06.hs, wherein you will do all of your programming.

To test your code, run the following shell commands to open a GHCi session:

$ stack repl
Configuring GHCi with the following packages: Ex06
Using main module: 1. Package 'Ex06' component exe:Ex06 ...
GHCi, version 8.2.2: http://www.haskell.org/ghc/  :? for help
[1 of 1] Compiling Ex06          (Ex06.hs, interpreted)
Ok, one module loaded.
*Ex06> let f = L "Hi " $ S $ L "! You're " $ I $ L "years old" $ X
*Ex06> printf f "Bob" 3
...

Note that you will only need to submit Ex06.hs, so only make changes to that file.

Download the Haskell for Mac project and unzip it somewhere on your local machine. Open the project in Haskell for Mac, and begin coding in Ex06.hs.

Note that you will only need to submit Ex06.hs, so only make changes to that file.

Recall the C function printf, which splices values into a special kind of string, called a format string:

// Prints "Hello Bob, you are 3 years old".
printf("Hello %s! you are %d years old!","Bob",3) 

The problem with this C function is that it's not type-safe. The types (and number) of the remaining arguments to printf are dependent on the value of first one – the format string. This makes encoding a printf style function in Haskell seem perhaps a bit more difficult than in less type-safe languages.

Note: For simplicity, our printf function will produce a pure String output rather than print to the screen.

General idea: Implement a GADT called Format for format strings, indexed by a type-level list of types required to fill the format string. Then, implement the printf function with the corresponding type.

1 Implement the Format GADT (4 Marks)

Instead of using plain old strings for our format strings, we're going to use a special data type, a GADT, indexed by a type-level list of types required by the format. Complete the following GADT, Format, using the examples below as a guide:

data Format (fmt :: [*]) where
  X :: Format '[]
  L :: {- your type here -}
  S :: {- your type here -} 
  I :: {- your type here -} 

The ' in front of the [] data constructor is important: it tells the compiler that the following constructor is a data constructor (namely the constructor for the empty list) which should be lifted to the type level. If you use the cons operator : on the type level, you will need to preceed it with ' as well.

1.1 Examples of Format Strings (and their types)

(L "Hello " (S (L "! You are " (I (L " years old!" X)))))
  :: Format '[String, Int]

Or, using the $ operator to make it clearer:

L "Hello " $ S $ L "! You are " $ I $ L " years old!" $ X
  :: Format '[String, Int]

Another example:

S $ S $ S $ I $ I $ I $ X
  :: Format
       '[String, String, String, Int, Int, Int]

And another:

L "Hello " $ L "World" $ X :: Format '[]

2 Implement printf (5 Marks)

Here is a type family we use to compute the type of printf given a format string:

type family FormatArgsThen (fmt :: [*]) (ty :: *) 
type instance FormatArgsThen '[] ty = ty
type instance FormatArgsThen (t ': fmt) ty = t -> FormatArgsThen fmt ty

Then, our printf function is simply of type:

printf :: Format fmt -> FormatArgsThen fmt String

You can see how this works by manually expanding the type family:

printf (L "Hello " $ S $ L "! You are " $ I $ L " years old!" $ X)
  :: FormatArgsThen '[String, Int] String
  :: String -> FormatArgsThen '[Int] String
  :: String -> Int -> FormatArgsThen '[] String
  :: String -> Int -> String

Actually implementing the printf function is harder than it looks, and that's where you come in. Implement the printf function so that it produces a string consisting of the argument values spliced in to the appropriate placeholders in the format string. You may find it helpful to define printf itself as:

printf :: Format fmt -> FormatArgsThen fmt String
printf f = printf' f ""

Where printf' is a function of similar type, except that it takes an additional string parameter for the "output so far" — the accumulator:

printf' :: Format fmt -> String -> FormatArgsThen fmt String
{- YOUR CODE HERE -}

3 Submission instructions

$ give cs3141 Ex06 Ex06.hs

on a CSE terminal, or by using the give web interface. Your file must be named Ex06.hs (case-sensitive!). A dry-run test will partially autotest your solution at submission time. To get full marks, you will need to perform further testing yourself.

2018-06-14 Thu 18:29

Announcements RSS